require "base_def"

local hand_pb_login = {}

--============================= local func start =============================--
--发消息给agent
local function SendMsg(fd, msgName, msgContent)
    SendPbMsgToWg("send", fd, {[msgName]=msgContent}, g_packId.hand_pb_login)
end

--登录检查状态
local function check_login_status(args)
    local channel = args.channel
    local login_type = args.login_type 

    --渠道登录状态
    local status_req = {'status'}
    local status_ret = CallMysqlRpc("GetChannelInfo", channel, status_req)
    log.info('GetChannelInfo:', status_ret)
    if status_ret and status_ret.status == 0 then
        --x渠道登录关闭
        return false, {err_msg = '渠道正在维护中'}
    elseif status_ret and (status_ret.status==2 and login_type==g_loginType.Guest) then
        --白名单时游客不允许登录
        return fasle, {err_msg = '游戏正在维护中'}
    end

    --服务器状态
    local status = CallMysqlRpc("CheckServiceStatus")
    log.info('CheckServiceStatus:', status)
    if status then
        --1正常2只允许白名单3准备停服4停服
        if status==1 or status==2 then    
            return true, {status = status}
        end
    end

    --登录方式状态
    local switch_req = {'login_type_switch'}        
    local switch_ret = CallMysqlRpc("GetChannelInfo", channel, switch_req)
    log.info('guest_login GetChannelInfo:', switch_ret)
    --1只允许正式玩家 2正式玩家和游客皆可
    if (switch_ret.login_type_switch==1 and login_type==g_loginType.Guest) then
        return false, {err_msg = '游客登录已关闭'} 
    end

    return false, {err_msg = '游戏正在维护中'}
end

local function get_userinfo_all(userid)
    local res 
    --取更详细的完整信息
    if IsGuest(userid) then
        res = CallRedisRpc('GetGuestInfo', userid)
    else
        res = CallMysqlRpc("GetUserAllInfo", userid)
    end
    if res==nil then
        log.error('get_userinfo_all error, userid:', userid)
        return
    end

    --这些参数都是需要string的
    res.gold = tostring(res.gold or 0)   
    res.safebox_coin = tostring(res.safebox_coin or 0)
    res.headimgurl = tostring(res.headimgurl or 0)

    --存进redis
    CallRedisRpc('SaveUserInfoCache', userid, res)

    return res
end

--安全信息请求
local function accout_safety_info(user_info)              
    local has_password
    local has_safe_password
    local has_bind_phone
    local last_login_time = os.time()
    local last_login_place

    if user_info then
        has_password = (user_info.password ~= nil)
        has_safe_password = (user_info.safe_code ~= nil)
        has_bind_phone = (user_info.phone_number ~= nil)
        last_login_place = user_info.lately_login_address
    end
    local res = {
        has_password = has_password,
        has_safe_password = has_safe_password,
        has_bind_phone = has_bind_phone,
        last_login_time = last_login_time,
        last_login_place = last_login_place
    }
    return res
end

--看是否有曾在房间里
local function ask_joined_gameinfo_req(userid)            
    local userRoomInfo = CallAgentInfo("CheckJoinGameInfo", {player_id = userid})
    if userRoomInfo then
        local res = {
            has = true,
            game_type = userRoomInfo.game_type,
            room_level = userRoomInfo.room_level,
            room_id = userRoomInfo.friend_room_id,
            club_id = userRoomInfo.club_id
        }
        return res
    end
end

--游客登录
local function guest_login(args)
    local login_info = CallRedisRpc("GetGusetId", args.account, args.channel)
    log.info('guest_login: ', login_info)
    --如果是游客第一次登录，把注册送的数据(如金币)加上
    if login_info.first_login then   
        local givenGold = CallMysqlRpc('GetChannelInfo', args.channel, {'gold_for_guest'})
        log.info("guest_login first_login giveGold=", givenGold)
        CallRedisRpc("RegisterUser", login_info.user_id, givenGold["gold_for_guest"])       
    end
    return login_info
end

--注册用户登录
local function user_login(args)
    local login_info
    local req = {
        account = args.account,                   --手机号或账号都行
        password = args.password,                 --验证码或密码
        channel = args.channel,                   --渠道
    }
    if args.login_type == g_loginType.Password then      
        --密码        
        req.password = crypt.base64encode(args.password or '')
        login_info = CallMysqlRpc("UserLogin", req)
        log.info("Password user_login userInfo=", login_info)
    elseif args.login_type == g_loginType.VerifyCode then 
        --验证码       
        local test_ver_code = skynet.getenv('phone_verify_code')
        local ok
        --传进来的不是测试验证码时去比对，是测试码时直接通过
        if test_ver_code~=args.ver_code then 
            --后续客户端把校验方式传过来 
            ok = CallShortMessageRpc("CheckVerifyCode", args.account, g_verType.login, args.ver_code)
            log.info("ok=", ok)
        else
            --测试验证码直接通过
            ok = true
        end
        --验证码通过后取玩家数据
        if ok then
            --log.info("")
            login_info = CallMysqlRpc("UserLogin", req)
            log.info("VerifyCode user_login userInfo=", login_info)
        else 
            login_info = { ["err_msg"] = "验证码错误"}
        end
    end

    --登录成功后用户数据后续可存入缓存中并返回token
    if login_info and (login_info.err_msg==nil) then   
        login_info.token = CallRedisRpc("SaveUserLogin", args.account, login_info.user_id, args.channel)    
    end

    return login_info
end

local function login_logic(args)
    --服务状态，为2时表明是只允许白名单登录，此时要判断一下
    local ok, status_info = check_login_status(args)
    log.info("status_info=", status_info)
    if not ok then
        return {err_msg = status_info.err_msg}
    end

    local login_info
    --token登录（token只是省去频繁的校验，后续在线人数较多时完善）
    --if args.token and args.token~='' then
    if nil then

    else    
        --帐号登录（old架构有token时这里传的0）
        if args.login_type==g_loginType.Guest or args.login_type==0 then
            --游客数据存在redis里
            login_info = guest_login(args)             
        else
            --正式玩家数据存在mysql里
            login_info = user_login(args)
        end
    end


    return login_info
end

--============================= hand_pb_login func start =============================--
--认证
function hand_pb_login.authen_req(fd, args)
    log.info("hand_pb_login.authen_req fd=", fd)
    log.info("hand_pb_login.authen_req authen_req=", args)

    local authed = false
    if args.secret == 'xfgame' then
        authed = true
    end
    --log.info("authed=", authed)
    if authed==true then
        local msg = {
            res = 'ok'
        }
        SendMsg(fd, "authen_res", msg)
    else
        log.error("authen_req authed = false !")
    end
end

--登录
function hand_pb_login.login_req(fd, args)
    log.info('handler_account, login_req: ', args)
    --根据本次登录类型(游客，注册用户)取玩家的user_id和token
    local res = login_logic(args)
    log.info('handler_account, login_res', res)

    --成功取到玩家ID和token后再取完整玩家信息并发给客户端
    if res and (res.err_msg==nil) then
        --取玩家完整信息并保存到redis
        local user_info = get_userinfo_all(res.user_id)
        log.info("user_info=", user_info)
        --发给客户端
        local login_res = {
            userid = res.user_id,
            token = res.token,
            user_info = user_info,
            safety_info = accout_safety_info(user_info),
            joined_game_info = {},
            --joined_game_info=ask_joined_gameinfo_req(res.user_id),
        }
        log.info("login_res=", login_res)
        SendMsg(fd, "login_res", login_res)

        --完成了登录并取得了玩家所有数据后，把这个agent注册到agent_info服务中
        user_info.fd = fd
	    CallAgentInfo("AgentLoginOk", user_info)

        --登陆成功后的活动逻辑(领金币等)
        --login_activity(res.user_id, res.channel)
    else
        local err_msg = "登录失败"
        if res and res.err_msg then
            err_msg = res.err_msg
        end
        SendMsg(fd, "kickout_notify", {code=2, des=err_msg})
    end

    return res and res.user_id
end

--只能包含数字或字母
local function check_input(str)
    if not str then return end
    for i = 1, string.len(str) do
        local v = string.byte(str, i)
        if not ((v >= 0x30 and v <= 0x39) or     
                (v >= 0x41 and v <= (0x41 + 25)) or
                (v >= 0x61 and v <= (0x61 + 25))) then
            return
        end
    end
    return true
end

--注册
function hand_pb_login.account_reg_req(fd, args)
    log.info("hand_pb_login.account_reg_req args=", args)
    --验证码       
    local test_ver_code = skynet.getenv('phone_verify_code')
    local ok
    --传进来的不是测试验证码时去比对，是测试码时直接通过
    if test_ver_code~=args.ver_code then 
        --后续客户端把校验方式传过来 
        ok = CallShortMessageRpc("CheckVerifyCode", args.account, g_verType.login, args.ver_code)
        log.info("ok=", ok)
    else
        --测试验证码直接通过
        ok = true
    end

    --验证码通过后校验格式
    if not check_input(args.account) then
        return {err_msg = '账号格式错误，请输入4-16位数的英文或数字'}
    end

    if not check_input(args.password) then
        return {err_msg = '密码格式错误，请输入6-16位数的英文或数字'}
    end

    --都通过后mysql新增账号
    local reg_info = CallMysqlRpc('UserReg', args)
    log.info("UserReg ret=", reg_info)
    if reg_info and not reg_info.err_msg then
        --注册成功后直接登录
        args.login_type = g_loginType.Password
        hand_pb_login.login_req(fd, args)
    else
        SendMsg(fd, "kickout_notify", {code=2, des=reg_info.err_msg})
    end
end

return hand_pb_login